import { Actions, Bubble, Sender, XStream, type BubbleProps } from "@ant-design/x"
import { Avatar, Button, Flex, message, Select, Space, Spin, Typography } from "antd"
import { useEffect, useState } from "react";
import { useLoaderData } from "react-router"
import type { ChatConversationResponse, ChatMessageResponse } from "../../../../api/welcome/type";
import { CopyOutlined, HistoryOutlined, UndoOutlined } from "@ant-design/icons";
import { conversationList, messageList, stream } from "../../../../api/welcome/agent";
import markdownit from 'markdown-it';
import React from "react";
import type { BubbleDataType } from "@ant-design/x/es/bubble/BubbleList";

const { Title } = Typography;
const md = markdownit({ html: true, breaks: true });


const renderMarkdown: BubbleProps['messageRender'] = (content) => {
  return (
    <Typography>
      {/* biome-ignore lint/security/noDangerouslySetInnerHtml: used in demo */}
      <div dangerouslySetInnerHTML={{ __html: md.render(content) }} />
    </Typography>
  );
};

const actionItems = [
  {
    key: 'copy',
    icon: <CopyOutlined />,
    label: '复制',
  },
];

const AIChat: React.FC = () => {
  const user = useLoaderData()
  const [content, setContent] = useState<string>();
  const [loading, setLoading] = useState<boolean>(false);
  const [messages, setMessages] = useState<ChatMessageResponse[]>([])
  const [lastMessage, setLastMessage] = useState<ChatMessageResponse>()
  const [chatConversations, setChatConversations] = useState<ChatConversationResponse[]>([])
  const [curConversation, setCurConversation] = useState<ChatConversationResponse>()

  const getChatConversations = async () => {
    const res = await conversationList(user?.id)
    if (res.code == 200) {
      setChatConversations(res.data)
    }
  }

  const getChatMessages = async (threadId: string) => {
    if (threadId) {
      const res = await messageList(threadId)
      if (res.code == 200) {
        setMessages(res.data)
      }
    }
  }

  const handlerSubmit = async () => {
    setLoading(true)
    let innerThreadId = curConversation?.threadId
    let innerTitle = curConversation?.title
    // 没有会话id创建
    if (!innerThreadId) {
      innerThreadId = crypto.randomUUID()
      innerTitle = content?.substring(0, 20)
      setChatConversations(pre => [{ threadId: innerThreadId, title: innerTitle }, ...pre])
      setCurConversation({ threadId: innerThreadId, title: innerTitle })
    }
    // 构建用户消息
    const humanMsg = {
      userId: user?.id,
      threadId: innerThreadId,
      title: innerTitle,
      role: 'human',
      content: content,
    }
    // 加入消息列表
    setMessages(old => [...old, humanMsg])
    setContent(undefined)

    // 发送流式请求
    const response = await stream(humanMsg)
    if (response.body) {
      // 消费SSE
      for await (const chunk of XStream({
        readableStream: response.body,
      })) {
        const data = JSON.parse(chunk.data)

        // 只显示message_chunk的消息
        if (chunk.event.trim() === "message_chunk") {
          // 如果当前消息还在流式中就流式加入，否则创建一个新的消息
          if (data.content) {
            setLastMessage(old => ({ ...data, content: old?.content ? `${old?.content}${data.content}` : data.content }))
          }

          // 如果有finish_reason就将该当前消息加入消息列表中
          if (data.finish_reason) {
            setLastMessage(pre => {
              setMessages(old => [...old, { ...pre, finalReason: data.finish_reason }])
              return undefined
            })
          }
        }
      }
    }
    setLoading(false)
  }

  useEffect(() => {
    getChatConversations()
  }, [])

  const handleClearContext = () => {
    setCurConversation(undefined)
    setLastMessage(undefined)
    setMessages([])
    setLoading(false)
    setContent(undefined)
    getChatConversations()
  }

  const handleChangeConversation = (value: string) => {
    setCurConversation(chatConversations.find(i => i.threadId == value))
    getChatMessages(value)
  }

  const handleClick = async (key: string, content?: string) => {
    if (key == 'copy' && content) {
      try {
        await navigator.clipboard.writeText(content);
        message.success('复制成功')
      } catch (error) {
        message.error("复制失败")

      }
    }
  }

  const getBubble = (item: ChatMessageResponse, key: number): BubbleDataType => {
    const base: BubbleDataType = {
      key: key,
      shape: "corner",
      variant: "shadow",
      role: item?.role,
      content: item?.content,
      messageRender: renderMarkdown,
      classNames: {
        content: '!bg-[#fff] !max-w-2/3'
      },
      placement: item?.role == 'human' ? 'end' : 'start',
    }
    if (item?.role == 'loading') {
      base.loading = true
      base.avatar = {}
    } else {
      base.header = item?.role != 'human' ? <strong> {item?.agent || 'unknown'}智能体</strong> : null
      base.footer = <Actions items={actionItems} onClick={({ key }: any) => handleClick(key, item?.content)} />
      base.avatar = item?.role != 'human' ? { icon: <Avatar src='./src/assets/fmt.png' /> } : undefined
    }
    return base
  }

  return <Flex gap="middle" vertical className="!h-full">
    <Select
      variant="borderless"
      disabled={loading}
      suffixIcon={<HistoryOutlined />}
      placeholder={<Title level={4}>新会话</Title>}
      value={curConversation?.threadId}
      onChange={handleChangeConversation}
      options={chatConversations.map(chatConversation => (
        {
          label: <Title level={4} ellipsis={{ tooltip: chatConversation.title }} >{chatConversation.title || '未知会话'}</Title>,
          value: chatConversation.threadId
        }
      ))}
    />
    <Bubble.List
      className="!h-[450px] !max-h-[450px] !overflow-auto !bg-[#f5f5f5] !rounded-xl p-2"
      items={(lastMessage ? [...messages, lastMessage] : loading ? [...messages, { role: "loading", content: "loading" }] : messages)
        .filter(item => item.content)
        .map((item: ChatMessageResponse, index: number) => getBubble(item, index))}
    />
    <Sender
      placeholder="欢迎使用智能电子图书助手!"
      loading={loading}
      readOnly={loading}
      value={content}
      onChange={setContent}
      onSubmit={handlerSubmit}
      actions={(_, info) => {
        const { SendButton, LoadingButton } = info.components;
        return (
          <Space size="small">
            <Button disabled={loading} type="text" icon={<UndoOutlined />} onClick={handleClearContext} />
            {loading ? (
              <LoadingButton type="default" icon={<Spin size="small" />} disabled />
            ) : (
              <SendButton type="primary" disabled={false} />
            )}
          </Space>
        );
      }}
    />
  </Flex>

}



export default AIChat